/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
package cgl.narada.wsinfra.wse.impl;

import java.util.Calendar;
import java.util.Enumeration;
import java.util.Vector;

import cgl.narada.wsinfra.WsMessageFlow;
import cgl.narada.wsinfra.WsProcessor;
import cgl.narada.wsinfra.exception.DeploymentException;
import cgl.narada.wsinfra.exception.IncorrectExchangeException;
import cgl.narada.wsinfra.exception.MessageFlowException;
import cgl.narada.wsinfra.exception.ParsingException;
import cgl.narada.wsinfra.exception.ProcessingException;
import cgl.narada.wsinfra.exception.UnknownExchangeException;
import cgl.narada.wsinfra.exception.WsFaultException;
import cgl.narada.wsinfra.schemas.addressing.ActionDocument;
import cgl.narada.wsinfra.schemas.addressing.EndpointReferenceType;
import cgl.narada.wsinfra.schemas.addressing.RelatesToDocument;
import cgl.narada.wsinfra.schemas.eventing.IdentifierDocument;
import cgl.narada.wsinfra.schemas.eventing.RenewResponseDocument;
import cgl.narada.wsinfra.schemas.eventing.SubscribeDocument;
import cgl.narada.wsinfra.schemas.eventing.SubscribeResponseDocument;
import cgl.narada.wsinfra.schemas.eventing.SubscriptionEndDocument;
import cgl.narada.wsinfra.schemas.soap.EnvelopeDocument;
import cgl.narada.wsinfra.util.QNameLocator;
import cgl.narada.wsinfra.wsa.AddressingHeaders;
import cgl.narada.wsinfra.wsa.ParseWsaHeaders;
import cgl.narada.wsinfra.wsa.WsaEprRules;
import cgl.narada.wsinfra.wsa.WsaFaultRules;
import cgl.narada.wsinfra.wsa.WsaProcessingFactory;
import cgl.narada.wsinfra.wse.WseActions;
import cgl.narada.wsinfra.wse.WseElementCreation;
import cgl.narada.wsinfra.wse.WseFaults;
import cgl.narada.wsinfra.wse.WseNodeUtils;
import cgl.narada.wsinfra.wse.WseProcessingFactory;
import cgl.narada.wsinfra.wse.WseQNames;
import cgl.narada.wsinfra.wse.WseResponseCreator;
import cgl.narada.wsinfra.wse.WseSource;
import cgl.narada.wsinfra.wse.matching.MatchingEngine;
import cgl.narada.wsinfra.wse.matching.SubscriptionEntry;
import cgl.narada.wsinfra.wse.matching.SubscriptionEntryFactory;
import cgl.narada.wsinfra.wse.matching.SubscriptionExpiryListener;
import cgl.narada.wsinfra.wse.matching.SubscriptionManagement;

/** This class which implements the interface that encapsulates the behavior
    of a WS-Eventing source node.

    @author Shrideep Pallickara
    $Date: 2005/07/29 22:41:30 $
    $Revision: 1.17 $
*/

public class WseSourceProcessor extends WsProcessor 
  implements WseSource, SubscriptionExpiryListener {
  private static final WseSourceProcessor instance = new WseSourceProcessor();
  private ParseWsaHeaders parseWsaHeaders;
  private WsaFaultRules wsaFaultRules;
  private WsaEprRules wsaEprRules;
 
  private WseActions wseActions;
  private WseQNames wseQNames;
  private WseFaults wseFaults;
  private WseNodeUtils wseNodeUtils;
  private WseResponseCreator wseResponseCreator;
  private WseElementCreation wseElementCreation;
  private SubscriptionManagement subscriptionManagement;
  private MatchingEngine matchingEngine;
  private SubscriptionEntryFactory subscriptionEntryFactory;

  private QNameLocator qNameLocator;
  private SourceSubscribeRequestProcessing subRequestProcessor;

  private EndpointReferenceType sourceEpr, subscriptionManagerEpr;

  private WsMessageFlow wsMessageFlow;
  private String moduleName = "WseSourceProcessor: ";



  private WseSourceProcessor() {
    parseWsaHeaders = WsaProcessingFactory.getParseWsaHeaders();
    wsaFaultRules =  WsaProcessingFactory.getWsaFaultRules();
    wsaEprRules = WsaProcessingFactory.getWsaEprRules();

    wseActions = WseActions.getInstance();
    wseQNames = WseQNames.getInstance();
    wseFaults = WseFaults.getInstance();
    wseNodeUtils = WseProcessingFactory.getWseNodeUtils();
    wseResponseCreator = WseProcessingFactory.getWseResponseCreator();
    wseElementCreation = WseProcessingFactory.getWseElementCreation();

    qNameLocator = QNameLocator.getInstance();
    subRequestProcessor = SourceSubscribeRequestProcessing.getInstance();

    subscriptionManagement = new SubscriptionManagement();
    matchingEngine = new MatchingEngine(subscriptionManagement);

    subscriptionEntryFactory = SubscriptionEntryFactory.getInstance();
  }

  public static WseSourceProcessor getInstance() {
    return instance;
  }

  /**
   * Retrieves the subscription management 
   * @return SubscriptionManagement
   */
  public SubscriptionManagement getSubscriptionManagement() {
	  return subscriptionManagement;
  }

  /** Sets the message flow which the processor should use */
  public void setMessageFlow(WsMessageFlow wsMessageFlow) 
    throws DeploymentException {
    this.wsMessageFlow = wsMessageFlow;
  }
  
  /** Gets the message flow which the processor should use. */
  public WsMessageFlow getMessageFlow() {
    return wsMessageFlow;
  }


  public void setSourceEPR(EndpointReferenceType sourceEpr) {
    this.sourceEpr = sourceEpr;
  }


  public void
  setSubscriptionManagerEPR(EndpointReferenceType subscriptionManagerEpr) {
    this.subscriptionManagerEpr = subscriptionManagerEpr;
  }



  /** Process the exchange. The argument also indicates the direction in
      which the exchange has actually traversed. */
  public boolean processExchange(EnvelopeDocument envelopeDocument,
				 int direction)
    throws UnknownExchangeException, IncorrectExchangeException,
    MessageFlowException, ProcessingException {

    AddressingHeaders addressingHeaders;
    try {
      addressingHeaders =
	parseWsaHeaders.getAddressingHeaders(envelopeDocument);
    } catch (ParsingException parseEx) {
      throw new ProcessingException(moduleName + "Unable to process. " +
				    "Problems related to parsing");
    }

    ActionDocument actionDocument = addressingHeaders.getAction();
    String action = null;
    if (actionDocument != null) {
      action = actionDocument.getAction().getStringValue();
    }
    
    checkExchangeType(action, direction);

    /** Only valid exchanges to be processed now remain */
    if (action == null) {
      processNotification(envelopeDocument, addressingHeaders);
      return false;
    }

       
    
    try {
      /** Process the subscribe request */
      if (action.equals(wseActions.getSubscribe()) ) {
	processSubscriptionRequest(envelopeDocument, addressingHeaders);
      } 
      
      /** This should have been received from the SubscriptionManager,
	  associated with the encapsulated subscription*/
      if (action.equals(wseActions.getUnsubscribeResponse()) ) {
	processUnsubscribe(envelopeDocument, addressingHeaders);
      }
      
      
      /** This should have been received from the SubscriptionManager,
	  associated with the encapsulated subscription*/
      if (action.equals(wseActions.getRenewResponse()) ) {
	processSubscriptionRenewal(envelopeDocument, addressingHeaders);
      }
      
    } catch (WsFaultException wsFaultException ) {
      EndpointReferenceType faultTo =
	wsaFaultRules.sendFaultTo(addressingHeaders);
      wsFaultException.setFaultTo(faultTo);
      manageFaultException(wsFaultException, direction);
      System.out.println(moduleName + wsFaultException);
    }

    return false;
  }
  

  private void
  processSubscriptionRequest(EnvelopeDocument envelopeDocument,
			     AddressingHeaders addressingHeaders)
    throws ProcessingException, WsFaultException, MessageFlowException  {

    SubscribeDocument subscribeDocument =
      wseNodeUtils.getSubscribeDocument(envelopeDocument);
    
    SubscribeResponseDocument subscribeResponseDoc =
      processSubscribeRequest(subscribeDocument);
    
    
    String requestType = "[wse:Subscribe]";
    EndpointReferenceType alternateEpr = null;
    EndpointReferenceType responseTo = 
      wseResponseCreator.getSendResponseTo(addressingHeaders,
					   alternateEpr, requestType);

    RelatesToDocument relatesTo = 
      wseResponseCreator.getResponseRelatesTo(addressingHeaders);
    
    EnvelopeDocument subResponseEnvelope =
      wseResponseCreator.createSubscribeResponse(responseTo, sourceEpr, 
						 relatesTo, 
						 subscribeResponseDoc);
						 
    System.out.println(moduleName + "The created SOAP envelope is\n\n\n" +
		       subResponseEnvelope);
    enrouteToNetwork(subResponseEnvelope);

    EnvelopeDocument subResponseForSubManager =
      subRequestProcessor.createEnvelopeForSubManager(sourceEpr,
						      subscriptionManagerEpr,
						      subscribeDocument,
						      subscribeResponseDoc);
    
    System.out.println(moduleName +
		       "The SOAPEnvelope for subscription Manager is\n\n\n" +
		       subResponseForSubManager);
    enrouteToNetwork(subResponseForSubManager);
  }


  

  /** The method to process a SubscriptionRequest issued by a Sink. If this
      request is successfully processed a SubscribeResponseDocument is issued.
      If the request is NOT successful a WsFaultException is thrown. */
  public SubscribeResponseDocument
  processSubscribeRequest(SubscribeDocument subscribeDocument)
    throws WsFaultException, ProcessingException {
    
    SubscriptionEntry subscriptionEntry = 
      subRequestProcessor.processSubscribeRequest(subscribeDocument,
						  subscriptionManagement,
						  sourceEpr,
						  subscriptionManagerEpr);
    
    SubscribeResponseDocument subscribeResponseDocument =
      wseElementCreation.newSubscribeResponseDocument(subscriptionEntry);
    
    System.out.println(moduleName + "The created subscribe response is\n\n" +
		       subscribeResponseDocument);
    return subscribeResponseDocument;
  }




  /** This method is used to update the subscription tables maintained at
      the source. ONLY requests successfully renewed by the
      SubscriptionManager are forwarded onto the source for updates at the
      source. This method will throw an error if the request was issued by
      anyone BUT the registered SubscriptionManager.
      
      wse:Identifier of the subscription.
      wse:From should match Subscription Manager for the subscription.
      wse:RenewResponse which would indicate the new expiry time for the
      subscription.
  */
  public void processSubscriptionRenewal(EnvelopeDocument envelopeDocument,
					 AddressingHeaders addressingHeaders)
    throws WsFaultException {

    RenewResponseDocument renewResponseDocument =
      wseNodeUtils.getRenewResponseDocument(envelopeDocument);
    RenewResponseDocument.RenewResponse renewResponse 
      = renewResponseDocument.getRenewResponse();


    IdentifierDocument idDocument =
      wseNodeUtils.getIdentifierDocument(envelopeDocument);
    String subscriptionId = idDocument.getIdentifier();
    System.out.println(moduleName + "Subscription identifier with request =>"
		       + subscriptionId);
    checkSubscriptionIdentifierForProblems(subscriptionId);
    
    SubscriptionEntry subscriptionEntry = 
      subscriptionManagement.getEntry(subscriptionId);
    
    if (renewResponse.isSetExpires()) {
      Calendar renewal = (Calendar) renewResponse.getExpires();
      subscriptionEntryFactory.updateSubscriptionEntry(subscriptionEntry, 
						       renewal);
    }
    
  }
  
  
  /** This method is used to update the subscription tables maintained at
      the source. Unsubscribe requests processed by the SubscriptionManager
      are forwarded onto the source for updates at the source. This method will
      throw an error if the request was issued by anyone BUT the registered
      SubscriptionManager for the subscription in question.
      
      wse:Identifier of the subscription
      wse:From shoould match SubscriptionManager for the subscription. */
  public void processUnsubscribe(EnvelopeDocument envelopeDocument,
				 AddressingHeaders addressingHeaders)
    throws WsFaultException {
    
    IdentifierDocument idDocument =
      wseNodeUtils.getIdentifierDocument(envelopeDocument);
    
    String subscriptionId = idDocument.getIdentifier();
    checkSubscriptionIdentifierForProblems(subscriptionId); 
    System.out.println(moduleName + "Trying to unsubscribe subscriptionID =>"
		       + subscriptionId);
    
    SubscriptionEntry subscriptionEntry =
      subscriptionManagement.deleteEntry(subscriptionId);    
  }


  /** This method is used to ensure the dissemination of a notification
      to registered subscriptions. */
  public void processNotification(EnvelopeDocument envelopeDocument,
				  AddressingHeaders addressingHeaders)
    throws ProcessingException, MessageFlowException {
    String errorReport = "";
    if (addressingHeaders.hasTo()) {
      errorReport = moduleName + "Notifications cannot contain a [wsa:To]" +
	" element. This information is generated seperately for each matched" +
	" destination by the WSE Source node.";
      throw new ProcessingException(errorReport);
    }
    
    boolean suppressDuplicates = true;
    Vector disseminationVector = 
      matchingEngine.performMatching(envelopeDocument, suppressDuplicates);

    int numOfDestinations = disseminationVector.size();
    if (numOfDestinations == 0) {
      System.out.println(moduleName + "No destinations to route the event");
      return;
    }

    Vector problemDestinations = new Vector();
    for (int i=0; i < numOfDestinations; i++) {
      EndpointReferenceType sinkEpr = 
	(EndpointReferenceType) disseminationVector.elementAt(i);
      /** We need to create a copy of the envelope since the header wiil
	  be added to in the next step. Successive additions leave their 
	  trace on the envelope -- something we wish to avoid. */
      EnvelopeDocument envelopeCopy= (EnvelopeDocument)envelopeDocument.copy();
      
      wsaEprRules.prepareSOAPEnvelope(envelopeCopy, sinkEpr);
      try {
	enrouteToNetwork(envelopeCopy);
      } catch (MessageFlowException mfe) {
	problemDestinations.addElement(sinkEpr);
      } 
    }

    if (problemDestinations.size() != 0) {
      errorReport = moduleName + "Out of (" + numOfDestinations + ") possible"+
	" destinations there were problems with routing notifications to (" +
	problemDestinations.size() + ") destinations." +
	"Problematic Epr(s) addresses are listed below\n";
      
      for (int i=0; i < problemDestinations.size() ; i++) {
	EndpointReferenceType sinkEpr = 
	(EndpointReferenceType) problemDestinations.elementAt(i);
	errorReport += sinkEpr.getAddress().getStringValue();
      } 
      
      throw new MessageFlowException(errorReport);
    }
  }



  /** Method that is called when one of the managed subscriptions expires */
  public void onSubscriptionExpiry(SubscriptionEntry expiredEntry) {
    if (expiredEntry == null) {
      System.out.println(moduleName + 
			 "Trying to expire a NULL subscription entry");
      return;
    }

    String subscriptionId = expiredEntry.getIdentifier();
    String status = 
      "http://schemas.xmlsoap.org/ws/2004/08/eventing/SubscriptionExpiry";
    String reason = "The subscription has expired!";
    
    String problems = terminateSubscription(subscriptionId, status, reason);
    if (problems != null) {
      System.out.println(problems);
    }
  }

  
  /** A source can also facilitate cancellation of subscriptions that aren't
      yet slated to expire. */
  public String 
  cancelSubscription(String subscriptionId, String additionalReason) {
    String problems = null;
    if (!subscriptionManagement.hasEntry(subscriptionId) ) {
      problems = moduleName + "Unknown subscription specified.";
      return problems;
    }
    
    SubscriptionEntry subscriptionEntry =
	subscriptionManagement.getEntry(subscriptionId);

    String status = 
      "http://schemas.xmlsoap.org/ws/2004/08/eventing/SourceCanceling";
    String reason = "The source is canceling this subscription [" +
      subscriptionId + "] though it is slated to expire at " + 
      subscriptionEntry.getExpiresAt() + ".\n";
    
    if (additionalReason != null) {
      reason += additionalReason;
    }
    
    problems = terminateSubscription(subscriptionId, status, reason);
    return problems;
  }
  

  /** This is called by the source when it is doing a planned shutdown of 
      the event source. All the subscriptions will be terminated and an
      appropriate SubscriptionEnd message will be sent to all the registered
      entities. */
  public void terminateServices() {
    Enumeration subscriptionIds = 
      subscriptionManagement.getSubscriptionIdentifiers();
    String status = 
      "http://schemas.xmlsoap.org/ws/2004/08/eventing/SourceShuttingDown";
    String reason = "The source is shutting down.!";
    while (subscriptionIds.hasMoreElements()) {
      String subscriptionId = (String) subscriptionIds.nextElement();
      String problems = terminateSubscription(subscriptionId, status, reason);
      if (problems != null) {
	System.out.println(problems);
      }
    }
    
    System.out.println(moduleName + 
		       "All the subscriptions have been terminated.");
  }
  
  


  /** Here we terminate the subscription. We first check to see if the
      subscriptionId is a valid one. Next, we create the appropriate
      subscriptionEnd. If there is a endTo that had been previously specified
      during the subscribe request, we send this endTo notification to that
      entity. If not, this message is sent to the sink. */
  private String 
  terminateSubscription(String subscriptionId, String status, String reason) {
    String errorReport = null;

    try {
      if (!subscriptionManagement.hasEntry(subscriptionId) ) {
	errorReport = moduleName + "Unknown subscription id [" +
	  subscriptionId + "] specified for termination.";
	return errorReport;
      }
      
      SubscriptionEntry subscriptionEntry =
	subscriptionManagement.deleteEntry(subscriptionId);
      
      SubscriptionEndDocument subscriptionEndDocument =
	wseElementCreation.newSubscriptionEndDocument(subscriptionEntry, 
						      status, reason);
      
      EndpointReferenceType endTo = subscriptionEntry.getEndTo();
      if (endTo == null) {
	endTo = subscriptionEntry.getSink();
      }
      
      EnvelopeDocument subscriptionEndEnvelope =
	wseResponseCreator.createSubscriptionEnd(endTo, sourceEpr, 
						 subscriptionEndDocument);
      enrouteToNetwork(subscriptionEndEnvelope);

      EndpointReferenceType subscriptionManager =
	subscriptionEntry.getSubscriptionManager();

      EnvelopeDocument subscriptionEndEnvelopeForSubMgr =
	wseResponseCreator.createSubscriptionEnd(subscriptionManager, 
						 sourceEpr, 
						 subscriptionEndDocument);
      enrouteToNetwork(subscriptionEndEnvelopeForSubMgr);

    } catch (ProcessingException pe) {
      errorReport = moduleName + "Processing Problems while trying " +
	"to terminate subscription [" + subscriptionId + "]\n" + 
	pe.toString();
    } catch (MessageFlowException mfe) {
      errorReport = moduleName + "MessageFlow Problems while trying " +
	"to terminate subscription [" + subscriptionId + "]\n" + 
	mfe.toString();
    }
    
    return errorReport;
  }

  public void issueSubscriptionEnd(String subscriptionId, String status, String reason)
  	throws ProcessingException, MessageFlowException {
	  
	  if (!subscriptionManagement.hasEntry(subscriptionId)) {
			String errorReport = moduleName + "Unknown subscription id ["
								+ subscriptionId + "] specified for termination.";
			throw new ProcessingException(errorReport);
		}

		SubscriptionEntry subscriptionEntry = 
			subscriptionManagement.deleteEntry(subscriptionId);

		SubscriptionEndDocument subscriptionEndDocument = 
			wseElementCreation.newSubscriptionEndDocument(subscriptionEntry, status,
																		 reason);

		EndpointReferenceType endTo = subscriptionEntry.getEndTo();
		if (endTo == null) {
			endTo = subscriptionEntry.getSink();
		}

		EnvelopeDocument subscriptionEndEnvelope = 
			wseResponseCreator.createSubscriptionEnd(endTo, sourceEpr, subscriptionEndDocument);
		enrouteToNetwork(subscriptionEndEnvelope);

		EndpointReferenceType subscriptionManager = 
			subscriptionEntry.getSubscriptionManager();

		EnvelopeDocument subscriptionEndEnvelopeForSubMgr = 
			wseResponseCreator.createSubscriptionEnd(subscriptionManager, sourceEpr,
															     subscriptionEndDocument);
		enrouteToNetwork(subscriptionEndEnvelopeForSubMgr);
	  
  }

  /** Check the specified subscription identifier for problems. Specifically
      throw an wse:InvalidFault if there are problems. */
  private void  
  checkSubscriptionIdentifierForProblems(String subscriptionIdentifier)
    throws WsFaultException {
    String faultReason = "";

    if (subscriptionIdentifier == null) {
      faultReason = "No subscription identifier has been specified or it is" +
	" NULL. Please check your request again.";
      throwInvalidMessageFault(faultReason);
    }

    if (!subscriptionManagement.hasEntry(subscriptionIdentifier)) {
      faultReason = "The specified subscription identifier [" +  
	subscriptionIdentifier + "] is not known to the SubscriptionManager."+
	" Please check your request again.";
      throwInvalidMessageFault(faultReason);
    }
  }


  /** Throw a WsFaultException, initialized with the invalid message QName
      and the specified reason */
  private void throwInvalidMessageFault(String reason)
    throws WsFaultException {

    throw
      new WsFaultException(wseFaults.getInvalidMessage(), reason);
  }


  private void checkExchangeType(String action, int direction)
    throws UnknownExchangeException, IncorrectExchangeException {

    if (direction == WsMessageFlow.FROM_NETWORK) {
      checkExchangeFromNetwork(action);
    }

    if (direction == WsMessageFlow.FROM_APPLICATION) {
      checkExchangeFromApplication(action);
    }

  }


  private void checkExchangeFromNetwork(String action)
    throws UnknownExchangeException, IncorrectExchangeException {
    String from = "Network. ";
    if (action == null) {
      throwUnknownExchangeException(action, from);
    }

    if (action.equals(wseActions.getSubscribeResponse()) ||
	action.equals(wseActions.getGetStatus()) ||
	action.equals(wseActions.getGetStatusResponse()) ||
	action.equals(wseActions.getRenew()) ||
	action.equals(wseActions.getSubscriptionEnd()) ) {
      throwIncorrectExchangeException(action, from);
    }

  }


  private void checkExchangeFromApplication(String action)
    throws UnknownExchangeException, IncorrectExchangeException {
    String from = "Application. ";
    if (action == null) {
      return;
    }

    if (action.equals(wseActions.getSubscribe()) ||
	action.equals(wseActions.getUnsubscribe()) ||
	action.equals(wseActions.getSubscribeResponse()) ||
	action.equals(wseActions.getGetStatus()) ||
	action.equals(wseActions.getGetStatusResponse()) ||
	action.equals(wseActions.getRenew()) ||
	action.equals(wseActions.getRenewResponse()) ) {
      throwIncorrectExchangeException(action, from);
    }

  }


  private void throwIncorrectExchangeException(String action, String from)
    throws IncorrectExchangeException {
    String reason =  moduleName +
      "Should NOT have received exchange corresponding to action [" +
      action + "] from the " + from;
    throw new IncorrectExchangeException(reason);
  }


  private void throwUnknownExchangeException(String action, String from)
    throws UnknownExchangeException {
    String reason =  moduleName +
      "No idea about processing exchange corresponding to action [" +
      action + "] from the " + from + ".";
    throw new UnknownExchangeException(reason);
  }

}








